home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 39
/
Aminet 39 (2000)(Schatztruhe)[!][Oct 2000].iso
/
Aminet
/
mus
/
play
/
DelfMPEG.lha
/
DelfMPEG
/
src
/
DelfMPEG.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-07-27
|
41KB
|
1,206 lines
/*****************************************************************************
DelfMPEG - MPEG audio player for Delfina DSP
Copyright (C) 1999, 2000 Michael Henke
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*****************************************************************************/
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/asyncio.h>
#include <proto/timer.h>
#include <proto/reqtools.h>
#include <exec/interrupts.h>
#include <exec/execbase.h>
#include <exec/memory.h>
#include <exec/libraries.h>
#include <libraries/asyncio.h>
#include <devices/timer.h>
#include <libraries/reqtools.h>
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
static UBYTE version[]="$VER: DelfMPEG 0.6 (Thu 27-Jul-2000)";
static UBYTE template[]=
"FILES/M,-V=VERBOSE/S,-N=NOPLAY/S,-T=SHOWTAG/S,-NL=NOFASTL/S,-NP=NOFASTP/S,"
"-F=FRAMEBUF/K/N,-A=ASYNCBUF/K/N,-FF=FFSKIP/K/N,-NT=NOTIMER/S,-M=MONO/S,"
"-S=STRICT/S,-D=DACRATE/K/N,-VOL=VOLUME/K/N,AREXX/S";
#define DEFAULT_FRAMEBUF 100
#define DEFAULT_ASYNCBUF 128
#define DEFAULT_FFSKIP 10
struct loadbuf {
ULONG header;
UWORD framesize, delfcopysize, crc, III_main_data_size;
UBYTE layer, mode, modext, freq, errprot, br_ind, II_jsbound, II_translate;
struct loadbuf *next;
UBYTE data[1728]; /* max: layer II, 384 kbps, 32 kHz -> 1728-4 bytes */
};
struct loadbuf *framebuf0=NULL, *curr_load, *curr_play;
LONG framebuf0size=0;
static ULONG mpg_freq[4]={44100,48000,32000,0};
static UBYTE *mpg_modename[4]={"stereo","j-stereo","dual-ch","single-ch"};
static UBYTE *mpg_layername[3]={"I","II","III"};
static UWORD mpg_bitrate[3][16]=
{ {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, /* I */
{0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0}, /* II */
{0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0} }; /* III */
static UWORD mpg_translate[3][2][16] =
{ { { 0,2,2,2,2,2,2,0,0,0,1,1,1,1,1,0 } , /* 44100 stereo */
{ 0,2,2,0,0,0,1,1,1,1,1,1,1,1,1,0 } } , /* 44100 mono */
{ { 0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0 } , /* 48000 stereo */
{ 0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0 } } , /* 48000 mono */
{ { 0,3,3,3,3,3,3,0,0,0,1,1,1,1,1,0 } , /* 32000 stereo */
{ 0,3,3,0,0,0,1,1,1,1,1,1,1,1,1,0 } } }; /* 32000 mono */
static UWORD mpg_sblimit[4]={27,30,8,12};
static ULONG ID3v1_TAG;
UBYTE ID3v1_buffer[142];
/** static LONG pow43tab[8206]; **/
#include "MP3_pow43tab.h"
/** static LONG quantab[512]; **/
#include "MP3_quantab.h"
static UWORD bitres_offset, bitres_ok;
static UBYTE bitres_buffer[4096];
#define MPG_MD_STEREO 0
#define MPG_MD_JOINT_STEREO 1
#define MPG_MD_DUAL_CHANNEL 2
#define MPG_MD_MONO 3
#define HDR_MPEG1 0xfff80000
#define HDR_CONSTANT 0x00060c00 /* layer, sampling frequency */
#define ID3V1 0x54414700 /* TAG */
#define ID3V2 0x49443300 /* ID3 */
#define XING_FLAG_FRAMES 1
#define XING_FLAG_BYTES 2
#define XING_FLAG_TOC 4
static UBYTE *delfina_name[8]=
{ "Classic","Lite","Pro","1200","Plus","UNKNOWN","UNKNOWN","UNKNOWN" };
extern struct DelfObj DSP56K_PCM;
extern struct DelfObj DSP56K_MP2;
extern struct DelfObj DSP56K_MP3;
#include <libraries/delfina.h>
#include "PCM.h"
#include "MP2.h"
#include "MP3.h"
extern struct ExecBase *SysBase;
struct Library *DelfinaBase=NULL;
struct Library *AsyncIOBase=NULL;
struct Library *TimerBase=NULL;
struct ReqToolsBase *ReqToolsBase=NULL;
struct AsyncFile *file;
struct FileInfoBlock *fib=NULL;
struct TagItem tag_done={TAG_DONE};
UBYTE rtfilename[128]={0};
struct Task *mytask;
ULONG bytes_total, bytes_loaded, buffers_filled, buffers_missed;
ULONG prevheader, currheader, frames_loaded, frames_played;
ULONG setpos_start, setpos_framesize;
ULONG decoder_busy, maindata_err, frames_js;
struct Interrupt delfint={0};
struct DelfPrg *prg_pcm=NULL, *prg_mp2=NULL, *prg_mp3=NULL;
struct DelfModule *mod_pcm=NULL;
DELFPTR mem_il_mp2=NULL, mem_ip_mp2=NULL, mem_y_mp3_quantab=NULL;
DELFPTR mem_il_mp3=NULL, mem_ip_mp3=NULL, mem_x_mp3_ro=NULL;
ULONG key=0;
UWORD *gb_pt, gb_buf, gb_num;
UBYTE xing_toc[100];
ULONG xingvbr, xing_flags, xing_frames;
ULONG channels,mono,freq,layer,pause,noplay,showtag,rexxmode;
ULONG verbose, ende, havetag, nofastl, nofastp, notimer, forcemono, strict;
LONG framebuf, asyncbuf, ffskip, dacrate, volume;
int rc=0;
/**
*** in arexx.c
**/
/* funtions */
char *initRexx(void);
void cleanupRexx(void);
void handleRexx(void);
/* variables */
extern char *rexxfilename[2];
extern char *portname;
extern WORD rexxstatus, rexxerror;
extern char rexxfiletypebuf[512];
extern ULONG rexxduration, rexxposition;
/*
**
** layer III - bit reservoir handling **
**
*/
UWORD BitReservoir(struct loadbuf *buf)
{
UWORD main_data_begin, i;
UBYTE *p0, *p1;
p1= &buf->data[0];
main_data_begin= (UWORD)(*p1)<<1 | (UWORD)(*(p1+1))>>7;
/*
** copy side information **
*/
p0= &bitres_buffer[0];
for(i=32; i>0; i--) *p0++= *p1++;
/*
** copy previous main_data **
*/
p0++; /* &bitres_buffer[33] */
if(bitres_offset>=main_data_begin)
{
bitres_ok=1;
p1=p0+bitres_offset-main_data_begin;
for(i=main_data_begin; i>0; i--) *p0++= *p1++;
bitres_offset=main_data_begin;
}
else
{
bitres_ok=0; /* not enough data in reservoir */
p0+=bitres_offset;
}
/*
** copy current main_data **
*/
i= mono ? 17 : 32; /* side info length */
p1= &buf->data[i]; /* begin of main_data area */
i= buf->delfcopysize-i; /* mainslots */
bitres_offset+= i;
for(; i>0; i--) *p0++= *p1++;
return(bitres_ok);
}
/*
**
** Delfina interrupt server **
**
*/
void __saveds IntServer(void)
{
if(pause)
{
/*
** mute **
*/
Delf_Run( prg_pcm->prog+PROG_PCM_MUTE, 0, DRUNF_ASYNCH, 0, 0, 0, 0 );
}
else
{
if(buffers_filled>0)
{
switch(layer)
{
case 2:
if( !Delf_Peek( prg_mp2->ydata+DATY_MP2_BUSY,DMEMF_YDATA ) )
{
/*
** send framedata to Delfina and launch MP2 decoder **
*/
Delf_CopyMem( &curr_play->data[0],
(void*)(prg_mp2->xdata+DATX_MP2_INBUF),
(ULONG)curr_play->delfcopysize,
DCPF_FROM_AMY|DCPF_XDATA|DCPF_24BIT );
Delf_Run( prg_mp2->prog+PROG_MP2_DECODE, 0, DRUNF_ASYNCH,
mono,
Delf_Peek(prg_pcm->ydata+DATY_PCM_BUFPTR,DMEMF_YDATA),
(ULONG)curr_play->II_translate,
(ULONG)curr_play->II_jsbound );
frames_played++;
buffers_filled--;
curr_play=curr_play->next;
}
else decoder_busy++;
break;
case 3:
if( !Delf_Peek( prg_mp3->ydata+DATY_MP3_BUSY,DMEMF_YDATA ) )
{
/*
** send framedata to Delfina and launch MP3 decoder **
*/
if(bitres_ok)
{
Delf_CopyMem( &bitres_buffer[0],
(void*)(prg_mp3->xdata+DATX_MP3_INBUF),
(ULONG)curr_play->III_main_data_size+33,
DCPF_FROM_AMY|DCPF_XDATA|DCPF_24BIT );
Delf_Run( prg_mp3->prog+PROG_MP3_DECODE, 0, DRUNF_ASYNCH,
mono,
Delf_Peek(prg_pcm->ydata+DATY_PCM_BUFPTR,DMEMF_YDATA),
(ULONG)curr_play->modext,
0 );
}
else maindata_err++;
frames_played++;
buffers_filled--;
curr_play=curr_play->next;
if(buffers_filled>0) BitReservoir(curr_play);
}
else decoder_busy++;
break;
default:
break;
}
}
else if(frames_loaded>1) buffers_missed++;
}
}
void initPCM(void)
{
if(!prg_pcm) return;
Delf_Run(prg_pcm->prog+PROG_PCM_INIT, 0, 0,
(ULONG)(forcemono?1:mono),
(volume>100) ? (volume*0x7fffff)/200 : (volume*0x400000)/100,
freq, 0 );
}
/*
**
** allocate Delfina resources **
**
*/
int InitDelfina(void)
{
if(noplay) return(0);
if(!(prg_pcm=Delf_AddPrg(&DSP56K_PCM)))
{
printf("**not enough Delfina memory\n");
return(0);
}
initPCM();
switch(layer)
{
case 2:
if(!nofastl)
mem_il_mp2=Delf_AllocMem(INTL_MP2_DATL, DMEMF_LDATA|DMEMF_INTERNAL|DMEMF_ALIGN_64);
if(!nofastp)
mem_ip_mp2=Delf_AllocMem(INTP_MP2_PROG, DMEMF_PROG|DMEMF_INTERNAL);
if(!(prg_mp2=Delf_AddPrg(&DSP56K_MP2)))
{
printf("**not enough Delfina memory\n");
return(0);
}
Delf_Run(prg_mp2->prog+PROG_MP2_INIT, 0, 0,
mem_il_mp2, mem_ip_mp2, 0, 0);
if((!mem_il_mp2 && !nofastl) || (!mem_ip_mp2 && !nofastp))
{
printf("**warning: not enough internal DSP memory\n"
" (the decoder might run too slowly and produce \"jerky\" sound)\n");
}
Delf_Poke(prg_mp2->ydata+DATY_MP2_FORCEMONO, DMEMF_YDATA, forcemono);
break;
case 3:
if(!nofastl)
mem_il_mp3=Delf_AllocMem(INTL_MP3_DATL, DMEMF_LDATA|DMEMF_INTERNAL|DMEMF_ALIGN_64);
if(!nofastp)
mem_ip_mp3=Delf_AllocMem(INTP_MP3_PROG, DMEMF_PROG|DMEMF_INTERNAL);
mem_x_mp3_ro=Delf_AllocMem(EXTX_MP3_RO,DMEMF_XDATA);
mem_y_mp3_quantab=Delf_AllocMem(EXTY_MP3_QUANTAB,DMEMF_YDATA);
prg_mp3=Delf_AddPrg(&DSP56K_MP3);
if(!prg_mp3 || !mem_x_mp3_ro || !mem_y_mp3_quantab)
{
printf("**not enough Delfina memory\n");
return(0);
}
Delf_CopyMem(pow43tab, (void*)(prg_mp3->ydata+DATY_MP3_POW43TAB),
8206*4, DCPF_FROM_AMY|DCPF_YDATA|DCPF_32BIT);
Delf_CopyMem(quantab, (void*)mem_y_mp3_quantab,
512*4, DCPF_FROM_AMY|DCPF_YDATA|DCPF_32BIT);
Delf_Run(prg_mp3->prog+PROG_MP3_INIT, 0, 0,
mem_il_mp3, mem_ip_mp3,
(ULONG)curr_play->freq,
(ULONG)mem_x_mp3_ro);
if((!mem_il_mp3 && !nofastl) || (!mem_ip_mp3 && !nofastp))
{
printf("**warning: not enough internal DSP memory\n"
" (the decoder might run too slowly and produce \"jerky\" sound)\n");
}
Delf_Poke(prg_mp3->xdata+DATX_MP3_QUANTAB_P, DMEMF_XDATA, mem_y_mp3_quantab);
Delf_Poke(prg_mp3->ydata+DATY_MP3_FORCEMONO, DMEMF_YDATA, forcemono);
break;
default:
printf("**layer %d is not supported\n",layer);
return(0);
}
delfint.is_Code=(void(*)(void))IntServer;
if (!(key=Delf_AddIntServer(prg_pcm->prog+PROG_PCM_INTKEY,&delfint)))
{
printf("**couldn't create interrupt server\n");
return(0);
}
if(!(mod_pcm=Delf_AddModule(DM_Inputs, 0,
DM_Outputs, 1,
DM_Code, prg_pcm->prog+PROG_PCM_MODULE,
DM_Freq, dacrate?dacrate*1000:freq,
DM_Name, "DelfMPEG", 0)))
{
printf("**couldn't create DelfModule\n");
return(0);
}
return(1);
}
/*
**
** free Delfina resources **
**
*/
void CleanupDelfina(void)
{
Delay(10);
if(mod_pcm) {Delf_RemModule(mod_pcm); mod_pcm=NULL;}
if(key) {Delf_RemIntServer(key); key=0;}
if(prg_mp2) {Delf_RemPrg(prg_mp2); prg_mp2=NULL;}
if(prg_mp3) {Delf_RemPrg(prg_mp3); prg_mp3=NULL;}
if(prg_pcm) {Delf_RemPrg(prg_pcm); prg_pcm=NULL;}
if(mem_il_mp2) {Delf_FreeMem(mem_il_mp2,DMEMF_LDATA|DMEMF_INTERNAL); mem_il_mp2=NULL;}
if(mem_ip_mp2) {Delf_FreeMem(mem_ip_mp2,DMEMF_PROG |DMEMF_INTERNAL); mem_ip_mp2=NULL;}
if(mem_il_mp3) {Delf_FreeMem(mem_il_mp3,DMEMF_LDATA|DMEMF_INTERNAL); mem_il_mp3=NULL;}
if(mem_ip_mp3) {Delf_FreeMem(mem_ip_mp3,DMEMF_PROG |DMEMF_INTERNAL); mem_ip_mp3=NULL;}
if(mem_x_mp3_ro) {Delf_FreeMem(mem_x_mp3_ro,DMEMF_XDATA); mem_x_mp3_ro=NULL;}
if(mem_y_mp3_quantab) {Delf_FreeMem(mem_y_mp3_quantab,DMEMF_YDATA); mem_y_mp3_quantab=NULL;}
}
UWORD GetBits(UWORD num)
{
UWORD val=0;
for(; num>0; num--)
{
if(gb_num==0)
{
gb_buf= *gb_pt++;
gb_num= 16;
}
gb_num--;
val+= val;
val|= (gb_buf>>gb_num)&1;
}
return(val);
}
UWORD CheckHeader(struct loadbuf *lb)
{
UWORD result=0;
/** let's ignore these header infos (we don't need them here)
*** ->version, ->extension, ->copyright, ->original, ->emphasis **/
lb->header = currheader;
lb->layer = 4-((currheader>>17)&0x3);
lb->mode = ((currheader>>6)&0x3);
lb->modext = ((currheader>>4)&0x3);
lb->br_ind = ((currheader>>12)&0xf);
lb->freq = ((currheader>>10)&0x3);
lb->errprot = ((currheader>>16)&0x1)^0x1;
if( (lb->layer==4) ||
(lb->br_ind==0) ||
(lb->br_ind==15)||
(lb->freq==3) ) result+=1;
if(prevheader)
if( (currheader&HDR_CONSTANT)!=(prevheader&HDR_CONSTANT) ||
((lb->mode==MPG_MD_MONO?1:2)!=channels) ) result+=2;
if((currheader&HDR_MPEG1)!=HDR_MPEG1) result+=4;
return(result);
}
/*
**
** analyze frame header and load frame **
**
*/
int ReadFrame(struct loadbuf *lb)
{
LONG s0,s1,i0,i1;
UWORD md;
if((md=CheckHeader(lb)))
{
if(!prevheader && strict)
{
printf("**not recognized as MPEG1 audio\n");
return(0);
}
if((currheader&0xffffff00)==ID3V1) printf(" (ID3v1 tag)\n");
else if(prevheader)
{
if(md&4) printf(" (lost frame sync - non-audio data)\n");
else if(md&1) printf(" (invalid frame header)\n");
else if(md&2) printf(" (unsupported frame header change)\n");
if(verbose)
printf("**position=0x%08lx currheader=0x%08lx "
"prevheader=0x%08lx\n",bytes_loaded,currheader,prevheader);
}
if(!strict)
{
s0=0;
while((s0<32*1024) && md)
{
bytes_loaded++; s0++;
currheader<<=8;
i0=ReadCharAsync(file);
if(i0<0) break;
else
{
currheader|=i0;
md=CheckHeader(lb);
}
}
printf("**skipped %d bytes - resync %s.\n",s0,md?"failed":"ok");
}
if(md) return(0); /* resync failed */
}
if(channels==0) channels=(lb->mode==MPG_MD_MONO)?1:2;
lb->II_translate= mpg_translate [lb->freq]
[(lb->mode==MPG_MD_MONO)?1:0]
[lb->br_ind];
lb->II_jsbound= (lb->mode==MPG_MD_JOINT_STEREO) ?
(lb->modext<<2)+4 : mpg_sblimit[lb->II_translate];
lb->framesize = (mpg_bitrate[lb->layer-1][lb->br_ind]*144000)
/mpg_freq[lb->freq] + ((currheader>>9)&0x1); /* padding */
lb->delfcopysize = lb->framesize-4;
s0=i0=2;
if(lb->errprot)
{
i0=ReadAsync(file,&lb->crc,s0);
lb->delfcopysize-=s0;
}
s1=i1=lb->delfcopysize;
/** do not read layer I frame because it might be too large !! **/
if(lb->layer>1) i1=ReadAsync(file,&lb->data[0],s1);
/*** at beginning of file: try to recognize the second frame, too ***/
if(!prevheader)
{
/** seek over first layer I frame (it has not been read) **/
if(lb->layer==1) i1=SeekAsync(file,s1,MODE_CURRENT);
if(PeekAsync(file,&currheader,4)==4)
{
ULONG ch=currheader;
prevheader=currheader;
if(CheckHeader(lb->next))
{
printf("** !!! not recognized as MPEG1 audio\n");
return(0);
}
prevheader=0;
currheader=ch;
}
}
if(!((i0==s0) && (i1==s1)))
{
if((i0==-1) || (i1==-1))
printf(" (file read error)\n");
else
if(verbose) printf(" (unexpected EOF - got %d of %d bytes)\n",i1,s1);
return(0);
}
if(lb->layer==3)
{
gb_pt= (UWORD*)&lb->data[2]; gb_num=0;
if(lb->mode==MPG_MD_MONO)
{
GetBits(9+5+4-16);
md=GetBits(12);
}
else
{
GetBits(9+3+8-16);
md=GetBits(12);
GetBits(59-12);
md+=GetBits(12);
GetBits(59-12);
md+=GetBits(12);
}
GetBits(59-12);
md+=GetBits(12);
lb->III_main_data_size=(md+7)>>3;
if(lb->mode!=MPG_MD_JOINT_STEREO) lb->modext=0;
if(lb->modext&1) frames_js++;
if(buffers_filled==0) BitReservoir(lb);
}
buffers_filled++;
frames_loaded++;
bytes_loaded+=lb->framesize;
return(1);
}
void setPosition(ULONG seconds) /*** WARNING: quick & dirty hack !! ***/
{
int loop,maxl;
if(strict) return;
pause++;
if(seconds>rexxduration) seconds=rexxduration;
/*printf("----setPosition %d\n",seconds);*/
if(xing_flags&XING_FLAG_TOC)
{
/*interpolate in TOC to get file seek point in bytes*/
int a;
float fa, fb, fx;
fx=100.0*(float)seconds/(float)rexxduration;
a=(int)fx; if(a>99) a=99;
fa=xing_toc[a];
if(a<99) fb=xing_toc[a+1]; else fb=256.0;
fx=(fa+(fb-fa)*(fx-a))/256.0;
bytes_loaded=(int)(fx*bytes_total);
frames_loaded=frames_played=seconds*freq/1152;
/*printf("----Xing VBR new pos: %ld of %ld bytes\n",bytes_loaded,bytes_total);*/
}
else
{
bytes_loaded=setpos_start+(seconds*(bytes_total-setpos_start))/rexxduration;
frames_loaded=frames_played=bytes_loaded/setpos_framesize;
/*printf("----plain new pos: %ld of %ld bytes\n",bytes_loaded,bytes_total);*/
}
curr_load=curr_play=framebuf0;
buffers_filled=0;
bitres_offset=0;
SeekAsync(file,bytes_loaded,MODE_START);
maxl=((framebuf>8) ? 8 : framebuf);
for(loop=0; loop<maxl; loop++)
{
ReadAsync(file,&currheader,4);
if(ReadFrame(curr_load))
{
prevheader=currheader;
curr_load=curr_load->next;
}
else {bytes_loaded=bytes_total; break;}
}
pause--;
}
int main(void)
{
struct RDArgs *rdargs;
LONG args[15]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, r1, i, taskpri;
UBYTE **files_pt, *filename;
double duration, duration2;
ULONG sigs, minutes, seconds, millisec, curr_print_pos, prev_print_pos;
struct timeval time1,time2;
struct rtFileRequester *rtfilereq=NULL;
struct rtFileList *rtfilelist=NULL, *rtfilelist_curr=NULL;
BPTR lock_newdir=NULL, lock_olddir=NULL;
/*
**
** read args **
**
*/
rdargs=ReadArgs(template,args,NULL);
printf("\33[1m%s by Smack/Infect!\33[0m\n",&version[6]);
files_pt=(char**)args[0];
verbose=args[1];
noplay=args[2];
showtag=args[3];
nofastl=args[4];
nofastp=args[5];
if(args[6]) framebuf=(*(LONG*)args[6]); else framebuf=DEFAULT_FRAMEBUF;
if(args[7]) asyncbuf=(*(LONG*)args[7]); else asyncbuf=DEFAULT_ASYNCBUF;
if(args[8]) ffskip=(*(LONG*)args[8]); else ffskip=DEFAULT_FFSKIP;
notimer=args[9];
forcemono=args[10];
strict=args[11];
if(args[12]) dacrate=(*(LONG*)args[12]); else dacrate=0;
if(args[13]) volume=(*(LONG*)args[13]); else volume=100;
rexxmode=args[14];
if(verbose)
printf(
"\n"
" DelfMPEG - MPEG audio player for Delfina DSP\n"
" Copyright (C) 1999, 2000 Michael Henke\n"
"\n"
" This program is free software; you can redistribute it and/or modify\n"
" it under the terms of the GNU General Public License as published by\n"
" the Free Software Foundation; either version 2 of the License, or\n"
" (at your option) any later version.\n"
"\n"
" This program is distributed in the hope that it will be useful,\n"
" but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
" GNU General Public License for more details.\n"
"\n"
" You should have received a copy of the GNU General Public License\n"
" along with this program; if not, write to the Free Software\n"
" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
"\n" );
/*
**
** open libraries & stuff **
**
*/
if(!noplay)
{
ULONG delfina_model;
double delfina_dspclock;
if (!(DelfinaBase=OpenLibrary("delfina.library",4)))
{
printf("**unable to open delfina.library V4\n");
rc=20;
goto exit_clean;
}
delfina_model=Delf_GetAttr(DA_HWInfo,0);
delfina_model&=0xff; i=0;
while(delfina_model) { delfina_model>>=1; i++; }
delfina_model=i ? (i-1) : 7;
if((DelfinaBase->lib_Version==4) && (DelfinaBase->lib_Revision<12))
delfina_dspclock=0.0;
else
delfina_dspclock=(double)Delf_GetAttr(DA_DSPClock,0)/1000000.0;
if(verbose)
printf("\n Delfina %s: delfina.library v%d.%d, %d K memory, %.1f MHz DSP\n",
delfina_name[delfina_model],
DelfinaBase->lib_Version,
DelfinaBase->lib_Revision,
(Delf_AvailMem(DMEMF_PROG|DMEMF_TOTAL)+Delf_AvailMem(DMEMF_YDATA|DMEMF_TOTAL)+1023)>>10,
delfina_dspclock );
}
if (!(AsyncIOBase=OpenLibrary("asyncio.library",39))) {
printf("**unable to open asyncio.library V39\n");
rc=20;
goto exit_clean;
}
TimerBase=(struct Library*)FindName(&SysBase->DeviceList,"timer.device");
mytask=FindTask(NULL);
if(!(fib=AllocDosObject(DOS_FIB,&tag_done)))
{
rc=20;
goto exit_clean;
}
if(rexxmode)
{
char *res;
if((res=initRexx()))
{
printf("**initRexx failed (%s)\n",res);
rc=20;
goto exit_clean;
}
}
/*
**
** init load buffers **
**
*/
if(framebuf<4) framebuf=4;
if(asyncbuf<4) asyncbuf=4;
if(ffskip<1) ffskip=1;
if(dacrate<0) dacrate=0;
if(dacrate>48) dacrate=48;
if(dacrate) dacrate=Delf_GetAttr(DA_Freq,dacrate*1000)/1000;
if(volume<0) volume=0;
if(volume>200) volume=200;
framebuf0size=framebuf*(LONG)sizeof(struct loadbuf);
if(verbose)
printf( "\n reader: framebuf=%d (%d K), asyncbuf=%d K, ffskip=%d, strict=o%s\n"
" decoder: forcemono=o%s, dacrate=%d kHz, volume=%d%%\n",
framebuf, (framebuf0size+1023)>>10, asyncbuf, ffskip, strict?"n":"ff",
forcemono?"n":"ff", dacrate, volume );
if(!(framebuf0=(struct loadbuf*)AllocMem(framebuf0size,MEMF_PUBLIC)))
{
printf("**not enough memory for \"framebuf\"\n");
rc=20;
goto exit_clean;
}
for(i=0;i<framebuf-1;i++) framebuf0[i].next= &framebuf0[i+1];
framebuf0[framebuf-1].next=framebuf0;
/*
**
** reqtools filerequester if no files specified **
**
*/
if(!files_pt && !rexxmode)
{
if((ReqToolsBase=(struct ReqToolsBase*)OpenLibrary("reqtools.library",38)))
{
if(!(rtfilereq=rtAllocRequest(RT_FILEREQ,NULL)))
{
rc=10;
goto exit_clean;
}
}
else
{
rc=5;
goto exit_clean;
}
}
rexxduration=rexxposition=0;
pause=1; rexxerror=0; /* initialize */
next_filereq:
if(rtfilereq)
{
rtfilelist=rtFileRequest( rtfilereq, &rtfilename[0],
"DelfMPEG: select MPEG audio files",
RTFI_Flags, FREQF_MULTISELECT|FREQF_PATGAD,
TAG_DONE );
if(rtfilelist)
{
rtfilelist_curr=rtfilelist;
if(rtfilereq->Dir)
{
lock_newdir=Lock(rtfilereq->Dir,SHARED_LOCK);
lock_olddir=CurrentDir(lock_newdir);
}
}
else goto exit_clean;
}
next_rexxloop:
if(rexxmode)
{
ende=1; rexxstatus=0; /* status: stop */
rexxfilename[0]=NULL;
printf("\n ARexx mode: waiting for 'PLAY <file>' on port '%s'\n",portname);
while(!rexxfilename[0])
{
handleRexx();
if(CheckSignal(SIGBREAKF_CTRL_D)) goto exit_clean;
if(ende>1) goto exit_clean; /* QUIT command */
Delay(1);
}
files_pt=rexxfilename;
rexxduration=rexxposition=0;
rexxfiletypebuf[0]=0;
rexxerror=0; /* PLAY command clears rexxerror */
rexxstatus=1; /* status: play */
if(pause>1) rexxstatus=2; /* status: pause */
}
ende=0;
/*
**
** files loop **
**
*/
do
{
/*
**
** get next filename **
**
*/
if(rtfilelist)
{
if(rtfilelist_curr)
{
filename=rtfilelist_curr->Name;
rtfilelist_curr=rtfilelist_curr->Next;
}
else filename=NULL;
}
else filename=(*files_pt++);
if(!filename) break;
printf("\n file: %s\n",filename);
havetag=0;
setpos_start=prev_print_pos=curr_print_pos=0;
curr_load=curr_play=framebuf0;
bytes_loaded=buffers_filled=buffers_missed=0;
prevheader=currheader=channels=0;
frames_loaded=frames_played=0;
decoder_busy=maindata_err=frames_js=0;
bitres_offset=0;
/*
**
** open file **
**
*/
rexxerror=20; /* file not found */
if((file=OpenAsync(filename,MODE_READ,asyncbuf<<10)))
{
/*
**
** read first frame + output some info **
**
*/
ExamineFH(file->af_File,fib);
bytes_total=fib->fib_Size;
ReadAsync(file,&currheader,4);
if(currheader==0x52494646) /* RIFF WAVE header */
{
UBYTE b[8];
ReadAsync(file,&b[0],8);
r1=20; /* 12+8 bytes */
while(1)
{
if(ReadAsync(file,&b[0],8)!=8) /* chunk name + length */
break; /* EOF -> ReadFrame() detects this */
r1=((LONG)b[7]<<24)|((LONG)b[6]<<16)|((LONG)b[5]<<8)|(LONG)b[4];
if((b[0]=='d')&&(b[1]=='a')&&(b[2]=='t')&&(b[3]=='a'))
break; /* found data chunk */
SeekAsync(file,r1,MODE_CURRENT); /* skip unknown chunk */
}
bytes_total=r1;
if(verbose)
printf(" found RIFF header (data chunk: %ld bytes)\n",r1);
ReadAsync(file,&currheader,4);
}
if((currheader&0xFFFFFF00)==ID3V2) /* found ID3V2 tag */
{
UBYTE b[6];
ReadAsync(file,&b[0],6);
r1=(LONG)b[5]|((LONG)b[4]<<7)|((LONG)b[3]<<14)|((LONG)b[2]<<21);
SeekAsync(file,r1,MODE_CURRENT);
r1+=10;
if(verbose)
printf(" skipped ID3v2.%d.%d tag (%d bytes)\n",
currheader&0xFF, b[0], r1);
bytes_loaded+=r1;
ReadAsync(file,&currheader,4);
}
rexxerror=30; /* file not recognized as MPEG1 audio */
if(ReadFrame(curr_load)) /* recognize the MPEG audio file */
{
if(showtag)
{
LONG oldpos;
oldpos=SeekAsync(file, -128, MODE_END);
ID3v1_TAG=0; havetag=0;
ReadAsync(file, &ID3v1_TAG, 3);
if((ID3v1_TAG&0xffffff00)==ID3V1)
{
ReadAsync(file,&ID3v1_buffer[00],30); /* title */
ReadAsync(file,&ID3v1_buffer[31],30); /* artist */
ReadAsync(file,&ID3v1_buffer[62],30); /* album */
ReadAsync(file,&ID3v1_buffer[93],04); /* year */
ReadAsync(file,&ID3v1_buffer[98],30); /* comment*/
ReadAsync(file,&ID3v1_buffer[141],1); /* genre */
for(i=0;i<140;i++)
{
if(ID3v1_buffer[i]<0x20) ID3v1_buffer[i]=0x20;
}
ID3v1_buffer[30]=0x00;
ID3v1_buffer[30+1+30]=0x00;
ID3v1_buffer[30+1+30+1+30]=0x00;
ID3v1_buffer[30+1+30+1+30+1+4]=0x00;
ID3v1_buffer[30+1+30+1+30+1+4+1+30]=0x00;
havetag=1;
}
SeekAsync(file, oldpos, MODE_START);
}
{ /* look for Xing VBR header */
UBYTE *xpt;
xingvbr=xing_flags=0;
xpt= &curr_load->data[0];
xpt+=(curr_load->mode==MPG_MD_MONO) ? 17 : 32;
if((xpt[0]=='X') &&
(xpt[1]=='i') &&
(xpt[2]=='n') &&
(xpt[3]=='g') )
{
xingvbr++;
xpt+=4;
xing_flags= (ULONG)xpt[0]<<24 | (ULONG)xpt[1]<<16 |
(ULONG)xpt[2]<<8 | (ULONG)xpt[3];
xpt+=4;
if(xing_flags&XING_FLAG_FRAMES)
{
xing_frames=(ULONG)xpt[0]<<24 | (ULONG)xpt[1]<<16 |
(ULONG)xpt[2]<<8 | (ULONG)xpt[3];
xpt+=4;
}
else xing_frames=0;
if(xing_flags&XING_FLAG_BYTES) xpt+=4;
if(xing_flags&XING_FLAG_TOC)
{
for(i=0;i<100;i++) xing_toc[i]=xpt[i];
}
if(verbose) printf(" Xing VBR header found (info: %d frames, TOC=%s)\n",xing_frames,((xing_flags&XING_FLAG_TOC)?"yes":"no"));
}
}
freq=mpg_freq[curr_load->freq];
mono=(curr_load->mode==MPG_MD_MONO) ? 1 : 0;
layer=curr_load->layer;
setpos_framesize=curr_load->framesize;
duration=(double)bytes_total/((double)freq/1152.0)/(double)curr_load->framesize;
r1=mpg_bitrate[layer-1][curr_load->br_ind];
if(xingvbr && xing_frames)
{
duration=(double)xing_frames*1152.0/(double)freq;
r1=(LONG)((double)bytes_total/duration/125.0);
}
sprintf(rexxfiletypebuf,
"layer %s %s%03d kbps %ld Hz %s",
mpg_layername[layer-1],
(xingvbr && xing_frames) ? "VBR avg. " : "",
r1,
freq,
mpg_modename[curr_load->mode] );
printf(" type: %s\n",rexxfiletypebuf);
rexxduration=(ULONG)(duration+0.5);
millisec=(ULONG)(1000.0*modf(duration,&duration2));
minutes=(ULONG)(duration2/60.0);
seconds=(ULONG)(duration2-minutes*60.0);
printf(" time: %02ld min %02ld.%03ld sec\n",minutes,seconds,millisec);
if(verbose) printf(" filesize/framesize: %ld/%ld bytes\n",bytes_total,curr_load->framesize);
if(showtag && havetag)
{
printf( " TAG ID3v1\n title: %s\n artist: %s\n"
" album: %s\n comment: %s\n"
" year: %s genre: %d\n",
&ID3v1_buffer[00], /* title */
&ID3v1_buffer[31], /* artist */
&ID3v1_buffer[62], /* album */
&ID3v1_buffer[98], /* comment*/
&ID3v1_buffer[93], /* year */
(int)ID3v1_buffer[141] ); /* genre */
}
prevheader=currheader;
curr_load=curr_load->next;
rexxerror=10; /* initDelfina failed */
if(InitDelfina())
{
rexxerror=0; /* ok */
printf(" playing..."); fflush(stdout);
taskpri=SetTaskPri(mytask,9);
GetSysTime(&time1);
if(pause>0) pause--;
/*
**
** frames loop **
**
*/
while(!ende)
{
if(rexxmode) handleRexx();
sigs=CheckSignal(SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D|SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F);
if(sigs&SIGBREAKF_CTRL_C)
{
printf(" break CTRL-C\n");
break; /* exit frames loop */
}
if(sigs&SIGBREAKF_CTRL_D)
{
ende=2;
printf(" break CTRL-D\n");
break; /* exit frames loop */
}
if(sigs&SIGBREAKF_CTRL_E)
{
if(pause)
{
pause=0;
rexxstatus=1; /* play */
printf("\n playing...");
}
else
{
pause=1;
rexxstatus=2; /* pause */
printf(" pause");
}
fflush(stdout);
}
if(sigs&SIGBREAKF_CTRL_F)
{
pause++;
i=ffskip;
while((buffers_filled>0) && (i>0))
{
curr_play=curr_play->next;
buffers_filled--; i--;
frames_played++;
if((layer==3) && (buffers_filled>0))
BitReservoir(curr_play);
}
pause--;
}
if( (buffers_filled<framebuf) &&
(bytes_loaded<bytes_total) )
{
if(ReadAsync(file,&currheader,4)==4)
if(ReadFrame(curr_load))
{
prevheader=currheader;
curr_load=curr_load->next;
}
else bytes_loaded=bytes_total; /* force EOF */
else bytes_loaded=bytes_total;
}
else
{
if( (bytes_loaded>=bytes_total) &&
(buffers_filled==0) )
{
printf(" done.\n");
break; /* exit frames loop */
}
if(!notimer) /* print timer */
{
curr_print_pos=(frames_played*1152)/freq;
if(prev_print_pos!=curr_print_pos)
{
rexxposition=curr_print_pos;
prev_print_pos=curr_print_pos;
printf("\r playing... (%02d:%02d)",
curr_print_pos/60, curr_print_pos%60);
fflush(stdout);
}
}
Delay(1);
}
}
pause++; /* mute output */
GetSysTime(&time2);
SetTaskPri(mytask,taskpri);
SubTime(&time2,&time1);
millisec=(ULONG)((double)time2.tv_micro/1000.0);
minutes=(ULONG)((double)time2.tv_secs/60.0);
seconds=(ULONG)((double)time2.tv_secs-minutes*60.0);
duration2=(double)time2.tv_secs+(double)time2.tv_micro/1000000.0;
if(verbose)
{
if(buffers_missed>5) /* prevent "unnecessary" warnings */
printf("**note: detected NO_INPUT_DATA %d times\n",buffers_missed);
if(decoder_busy>0)
printf("**note: detected DECODER_BUSY %d times (%d%%)\n",decoder_busy,decoder_busy*100/frames_played);
if(maindata_err>0)
printf("**note: detected MP3_MAINDATA_ERROR %d times\n",maindata_err);
if(frames_js>0)
printf("**note: unsupported INTENSITY_STEREO frames: %d (%d%%)\n",frames_js,frames_js*100/frames_loaded);
printf(" frames played/loaded: %ld/%ld\n",frames_played,frames_loaded);
printf(" elapsed time: %02ld min %02ld.%03ld sec\n",minutes, seconds, millisec);
}
}
CleanupDelfina();
}
CloseAsync(file);
}
else printf("**unable to open file\n");
} while(!ende);
if(rtfilelist)
{
if(lock_olddir) { CurrentDir(lock_olddir); lock_olddir=NULL; }
if(lock_newdir) { UnLock(lock_newdir); lock_newdir=NULL; }
rtFreeFileList(rtfilelist); rtfilelist=NULL;
if(ende<2) goto next_filereq;
}
if(rexxmode && (ende<2)) goto next_rexxloop;
exit_clean:
cleanupRexx();
if(rdargs) FreeArgs(rdargs);
if(framebuf0) FreeMem((APTR)framebuf0,framebuf0size);
if(fib) FreeDosObject(DOS_FIB,fib);
if(rtfilereq) rtFreeRequest(rtfilereq);
if(ReqToolsBase) CloseLibrary((struct Library*)ReqToolsBase);
if(AsyncIOBase) CloseLibrary(AsyncIOBase);
if(DelfinaBase) CloseLibrary(DelfinaBase);
return(rc);
}